Imports System.Xml
Imports System.Xml.XPath
Imports System.Web
Imports System.Net

Public Class clsProjectInfo
    Public ReadOnly Property IsEmpty() As Boolean
        Get
            If colProjects.Count = 0 Then
                Return True
            Else
                Return False
            End If
        End Get
    End Property
    Public Event GetIsDone()
#Region "Declarations for collections and file downloading"
    Public urlPsummary As String = "http://fah-web.stanford.edu/psummary.html"
    Public urlBeta As String = "http://fah-web.stanford.edu/psummaryC.html"
    Private fileXML As String = ""
    'Parsing constants
    Private Const parseHeader As String = "<TD>Contact</TD>"
    Private Const parseEnd As String = "</TABLE>"
    'private properties
    Public Structure sProject
        Public ProjectNumber As String, ServerIP As String, WUName As String, NumberOfAtoms As String, PreferredDays As String, FinalDeadline As String
        Public Credit As String, Frames As String, Code As String, Description As String, Contact As String, ParsedAt As DateTime, PersonalNotes As String
    End Structure
    Public Function Compare(ByVal cProject As sProject, ByVal oProject As sProject) As Boolean
        Try
            If Not cProject.ProjectNumber = oProject.ProjectNumber Then Return False
            If Not cProject.ServerIP = oProject.ServerIP Then Return False
            If Not cProject.WUName = oProject.WUName Then Return False
            If Not cProject.NumberOfAtoms = oProject.NumberOfAtoms Then Return False
            If Not cProject.PreferredDays = oProject.PreferredDays Then Return False
            If Not cProject.FinalDeadline = oProject.FinalDeadline Then Return False
            If Not cProject.Credit = oProject.Credit Then Return False
            If Not cProject.Frames = oProject.Frames Then Return False
            If Not cProject.Code = oProject.Code Then Return False
            If Not cProject.Description = oProject.Description Then Return False
            If Not cProject.Contact = oProject.Contact Then Return False
            Return True
        Catch ex As Exception
            Return False
        End Try
    End Function
    Public ReadOnly Property PPD(ByVal Project As String, ByVal FrameTime As TimeSpan) As Double
        Get
            Try
                If Not KnownProject(Project) Or FrameTime.TotalSeconds = 0 Then Return 0
                Dim iPworth As Double = CDbl(ProjectInfo.Project(Project).Credit)
                iPworth = iPworth / 10000
                'How many frames per 24/h
                Dim iPPD As Double = 0
                Dim tsDay As TimeSpan = TimeSpan.FromDays(1)
                Do
                    If tsDay.Subtract(FrameTime).TotalSeconds >= 0 Then
                        iPPD += iPworth
                        tsDay = tsDay.Subtract(FrameTime)
                    Else
                        Exit Do
                    End If
                Loop
                'get fraction of _tsFrame to be done in remaining seconds
                Dim iRfraction As Double
                If tsDay.TotalSeconds > 0 Then
                    iRfraction = tsDay.TotalSeconds / FrameTime.TotalSeconds
                    iPPD += iRfraction * iPworth
                End If
                Return (Math.Round(iPPD, 4))
            Catch ex As Exception
                LogWindow.WriteError("clsProjectInfo, PPD(" & Project & "-ts=" & FrameTime.ToString & ")", Err, ex.Message)
            End Try
        End Get
    End Property
    Public Function AddProject(ByVal Project As sProject) As Boolean
        Try
            If colProjects.Contains(Project.ProjectNumber) Then Return False
            colProjects.Add(Project, Project.ProjectNumber)
            WriteXML()
            Return True
        Catch ex As Exception
            Return False
        End Try
    End Function
    Private colProjects As New Collection
    Public ReadOnly Property ProjectNumber(ByVal Ind As Int16) As String
        Get
            Try
                Dim rP As sProject = colProjects(Ind)
                Return rP.ProjectNumber
            Catch ex As Exception
                Return vbNullString
            End Try
        End Get
    End Property
    Public ReadOnly Property KnownProject(ByVal ProjectNumber As String) As Boolean
        Get
            Try
                Return colProjects.Contains(ProjectNumber)
            Catch ex As Exception
                Return False
            End Try
        End Get
    End Property
    Public ReadOnly Property ProjectCount() As Integer
        Get
            Return colProjects.Count
        End Get
    End Property
    Public ReadOnly Property Project(ByVal ProjectNumber) As sProject
        Get
            Try
                Return colProjects(ProjectNumber)
            Catch ex As Exception
                Return Nothing
            End Try
        End Get
    End Property
    Public Function RemoveProject(ByVal ProjectNumber) As Boolean
        Try
            If colProjects.Contains(ProjectNumber) Then
                colProjects.Remove(ProjectNumber)
                Return (Not colProjects.Contains(ProjectNumber))
            Else
                Return False
            End If
        Catch ex As Exception
            Return False
        End Try
    End Function
    Private Function IndexOfProject(ByVal ProjectNumber As String) As Int16
        If Not KnownProject(ProjectNumber) Then Return -1
        For xInt As Int16 = 1 To colProjects.Count
            If CType(colProjects(xInt), sProject).ProjectNumber = ProjectNumber Then Return xInt
        Next
        Return -1
    End Function
    Public Function UpdateProject(ByVal Project As sProject) As Boolean
        Try
            If Not KnownProject(Project.ProjectNumber) Then Return False
            Project.PersonalNotes = "Edited manually at " & DateTime.Now.ToLongDateString & "-" & DateTime.Now.ToShortTimeString
            Dim intIndex As Int16 = IndexOfProject(Project.ProjectNumber)
            colProjects.Remove(intIndex)
            colProjects.Add(Project, Project.ProjectNumber, intIndex)
            Return CType(colProjects(intIndex), sProject).PersonalNotes = Project.PersonalNotes
        Catch ex As Exception
            Return False
        End Try
    End Function
   
    Public Function ParseFile(ByVal FileName As String) As Boolean
        Try
            Dim AllText As String = IO.File.ReadAllText(FileName)
            If InStr(AllText, parseHeader) = 0 Then
                Return False
            Else
                AllText = Mid(AllText, InStr(AllText, parseHeader) + Len(parseHeader))
            End If
            If ParseProjects(AllText) Then
                WriteXML()
                Return True
            Else
                Return False
            End If
        Catch ex As Exception
            Return False
        End Try
    End Function
    Public Function GetProjects() As Boolean
        Try
            mySettings.dtLastProjectUpdate = DateTime.Now
            'check for network
            Dim Url As String
            If bBetaTeam Then
                Url = urlBeta
            Else
                Url = urlPsummary
            End If
            If modMAIN.FAHWEB_Failure <> DateTime.MinValue Then
                If DateTime.Now.Subtract(modMAIN.FAHWEB_Failure).TotalMinutes < 15 Then
                    LogWindow.WriteLog("Attempt to get projects aborted, last failure less then 15 minutes ago.")
                    Return False
                Else
                    Try
                        Dim strPing As String = "fah-web.stanford.edu"
                        If Not My.Computer.Network.Ping(strPing) Then
                            LogWindow.WriteLog("fah-web.stanford.edu could not be pinged, aborting update for projectinformation.")
                            modMAIN.FAHWEB_Failure = DateTime.Now
                            Return False
                        Else
                            modMAIN.FAHWEB_Failure = DateTime.MinValue
                        End If
                    Catch ex As Exception
                        LogWindow.WriteError("clsProjectInfo, Getprojects, ping url", Err)
                        modMAIN.FAHWEB_Failure = DateTime.Now
                        Return False
                    End Try
                End If
            End If
            

            Dim allText As String = vbNullString
            Try
                Dim mC As WebClient = New WebClient
                allText = mC.DownloadString(Url)
            Catch ex As Exception
                Return False
            End Try
            If InStr(allText, parseHeader) = 0 Then
                Return False
            Else
                allText = Mid(allText, InStr(allText, parseHeader) + Len(parseHeader))
            End If
            If Not ParseProjects(allText) Then
                colProjects.Clear()
                ReadXML()
                Return False
            End If
            WriteXML()
            RaiseEvent GetIsDone()
            Return True
        Catch ex As Exception
            Return False
        End Try
    End Function
    Private Function ParseProjects(ByVal allText As String) As Boolean
        Try
            Dim colKey As String ' every collection key is the projectnumber
            Dim strTmp As String ' needed because parsing in one time is sh1t
            Do
                'Cut to after <TD>
                Try
                    allText = Mid(allText, InStr(allText, "<TD>") + 4)
                    colKey = Mid(allText, 1, InStr(allText, "</TD>") - 1).Trim
                    If Not colProjects.Contains(colKey) Then
                        Dim nProject As New sProject
                        With nProject
                            .ProjectNumber = colKey
                            'set blank
                            .WUName = "" : .ServerIP = "" : .PreferredDays = "" : .PersonalNotes = "" : .ParsedAt = DateTime.Now : .NumberOfAtoms = "" : .Frames = "" : .FinalDeadline = "" : .Code = "" : .Contact = "" : .Credit = "" : .Description = ""
                            'Cut to after <TD>
                            allText = Mid(allText, InStr(allText, "<TD>") + 4)
                            If Mid(allText, 1, InStr(allText, "</TD>") - 1).Trim <> "" Then .ServerIP = Mid(allText, 1, InStr(allText, "</TD>") - 1).Trim
                            'Cut to after <TD>
                            allText = Mid(allText, InStr(allText, "<TD>") + 4)
                            If Mid(allText, 1, InStr(allText, "</TD>") - 1).Trim <> "" Then .WUName = Mid(allText, 1, InStr(allText, "</TD>") - 1).Trim
                            'Cut to after <TD>
                            allText = Mid(allText, InStr(allText, "<TD>") + 4)
                            If Mid(allText, 1, InStr(allText, "</TD>") - 1).Trim <> "" Then .NumberOfAtoms = Mid(allText, 1, InStr(allText, "</TD>") - 1).Trim
                            'Cut to after <TD>
                            allText = Mid(allText, InStr(allText, "<TD>") + 4)
                            If Mid(allText, 1, InStr(allText, "</TD>") - 1).Trim <> "" Then .PreferredDays = Mid(allText, 1, InStr(allText, "</TD>") - 1).Trim
                            'Cut to after <TD>
                            allText = Mid(allText, InStr(allText, "<TD>") + 4)
                            If Mid(allText, 1, InStr(allText, "</TD>") - 1).Trim <> "" Then .FinalDeadline = Mid(allText, 1, InStr(allText, "</TD>") - 1).Trim
                            'Cut to after <TD>
                            allText = Mid(allText, InStr(allText, "<TD>") + 4)
                            If Mid(allText, 1, InStr(allText, "</TD>") - 1).Trim <> "" Then .Credit = Mid(allText, 1, InStr(allText, "</TD>") - 1).Trim
                            'Cut to after <TD>
                            allText = Mid(allText, InStr(allText, "<TD>") + 4)
                            If Mid(allText, 1, InStr(allText, "</TD>") - 1).Trim <> "" Then .Frames = Mid(allText, 1, InStr(allText, "</TD>") - 1).Trim
                            'Cut to after <TD>
                            allText = Mid(allText, InStr(allText, "<TD>") + 4)
                            If Mid(allText, 1, InStr(allText, "</TD>") - 1).Trim <> "" Then .Code = Mid(allText, 1, InStr(allText, "</TD>") - 1).Trim
                            'Cut to after <TD>
                            allText = Mid(allText, InStr(allText, "<TD>") + 4)
                            strTmp = Mid(allText, 1, InStr(allText, "</TD>") - 1).Trim
                            'Looks like "<a href=http://fah-web.stanford.edu/cgi-bin/fahproject?p=772>Description</a>"
                            If Mid(allText, 1, InStr(allText, "</TD>") - 1).Trim <> "" Then .Description = Mid(strTmp, InStr(strTmp, "http"), InStr(strTmp, ">Des") - 9)
                            'Cut to after <TD>
                            allText = Mid(allText, InStr(allText, "<TD>") + 4)
                            strTmp = Mid(allText, 1, InStr(allText, "</TD>") - 1).Trim
                            'looks like "<font size=-1>vvishal</font>"
                            strTmp = Mid(strTmp, InStr(strTmp, ">") + 1)
                            .Contact = Mid(strTmp, 1, Len(strTmp) - 7)
                            .ParsedAt = DateTime.Now.ToLongDateString & "-" & DateTime.Now.ToShortTimeString
                        End With
                        colProjects.Add(nProject, colKey)
                    Else
                        'cut alltext
                        For tentimes As Int16 = 1 To 10
                            allText = Mid(allText, InStr(allText, "<TD>") + 4)
                        Next
                    End If
                Catch ex As Exception
                    Console.WriteLine(ex.Message)
                    'hehe no doubles :D
                End Try
                If InStr(allText, "<TD>") = 0 Then Exit Do
            Loop
            Return True
        Catch ex As Exception
            Debug.Print(ex.Message)
            Return False
        End Try
    End Function
    Private Sub WriteXML()
        If My.Computer.FileSystem.FileExists(fileXML) Then My.Computer.FileSystem.DeleteFile(fileXML)
        Dim xSettings As New XmlWriterSettings
        xSettings.Indent = True
        xSettings.IndentChars = "    "
        Dim xWriter As XmlWriter = XmlWriter.Create(fileXML, xSettings)
        xWriter.WriteStartElement("Projects")
        xWriter.WriteStartElement("Count")
        xWriter.WriteString(colProjects.Count.ToString)
        xWriter.WriteEndElement()
        For Each nProject As sProject In colProjects
            With xWriter
                .WriteStartElement("Project")
                .WriteStartElement("Projectnumber")
                .WriteString(nProject.ProjectNumber)
                .WriteEndElement()
                .WriteStartElement("ServerIP")
                .WriteString(nProject.ServerIP)
                .WriteEndElement()
                .WriteStartElement("WorkunitName")
                .WriteString(nProject.WUName)
                .WriteEndElement()
                .WriteStartElement("NumberOfAtoms")
                .WriteString(nProject.NumberOfAtoms)
                .WriteEndElement()
                .WriteStartElement("PreferredDays")
                .WriteString(nProject.PreferredDays)
                .WriteEndElement()
                .WriteStartElement("FinalDeadline")
                .WriteString(nProject.FinalDeadline)
                .WriteEndElement()
                .WriteStartElement("Credit")
                .WriteString(nProject.Credit)
                .WriteEndElement()
                .WriteStartElement("Frames")
                .WriteString(nProject.Frames)
                .WriteEndElement()
                .WriteStartElement("Code")
                .WriteString(nProject.Code)
                .WriteEndElement()
                .WriteStartElement("Description")
                .WriteString(nProject.Description)
                .WriteEndElement()
                .WriteStartElement("Contact")
                .WriteString(nProject.Contact)
                .WriteEndElement()
                .WriteStartElement("ParsedAt")
                .WriteString(nProject.ParsedAt.ToShortDateString)
                .WriteEndElement()
                .WriteStartElement("PeronalNote")
                .WriteString(nProject.PersonalNotes)
                .WriteEndElement()
                .WriteEndElement()
            End With
        Next
        xWriter.WriteEndElement()
        xWriter.Close()
    End Sub
    Public Function ReadXML() As Boolean
        Try
            Dim Xreader As XmlReader = XmlReader.Create(fileXML)
            Dim intCount As Int16
            'Clean collections
            Xreader.ReadStartElement("Projects")
            Xreader.ReadStartElement("Count")
            intCount = CInt(Xreader.ReadString)
            Xreader.ReadEndElement()
            For Counter As Int16 = 1 To intCount
                Dim nProject As New sProject
                With Xreader
                    .ReadStartElement("Project")
                    .ReadStartElement("Projectnumber")
                    nProject.ProjectNumber = .ReadString
                    .ReadEndElement()
                    .ReadStartElement("ServerIP")
                    nProject.ServerIP = .ReadString
                    .ReadEndElement()
                    .ReadStartElement("WorkunitName")
                    nProject.WUName = .ReadString
                    .ReadEndElement()
                    .ReadStartElement("NumberOfAtoms")
                    nProject.NumberOfAtoms = .ReadString
                    .ReadEndElement()
                    .ReadStartElement("PreferredDays")
                    nProject.PreferredDays = .ReadString
                    .ReadEndElement()
                    .ReadStartElement("FinalDeadline")
                    nProject.FinalDeadline = .ReadString
                    .ReadEndElement()
                    .ReadStartElement("Credit")
                    nProject.Credit = .ReadString
                    .ReadEndElement()
                    .ReadStartElement("Frames")
                    nProject.Frames = .ReadString
                    .ReadEndElement()
                    .ReadStartElement("Code")
                    nProject.Code = .ReadString
                    .ReadEndElement()
                    .ReadStartElement("Description")
                    nProject.Description = .ReadString
                    .ReadEndElement()
                    .ReadStartElement("Contact")
                    nProject.Contact = .ReadString
                    .ReadEndElement()
                    .ReadStartElement("ParsedAt")
                    nProject.ParsedAt = CDate(.ReadString)
                    .ReadEndElement()
                    .ReadStartElement("PeronalNote")
                    nProject.PersonalNotes = .ReadString
                    .ReadEndElement()
                    .ReadEndElement()
                    colProjects.Add(nProject, nProject.ProjectNumber)
                End With
            Next
            Xreader.Close()
            Return True
        Catch ex As Exception
            Return False
        End Try
    End Function
    Public Function Purge() As Boolean
        Try
            colProjects.Clear()
            My.Computer.FileSystem.DeleteFile(fileXML)
            GetProjects()
            Return (ProjectCount > 0)
        Catch ex As Exception
            Return False
        End Try
    End Function
    Public Sub New(ByVal DataLocation As String)
        DataLocation = DataLocation.TrimEnd("\")
        fileXML = DataLocation & "\Projects.xml"
        If My.Computer.FileSystem.FileExists(fileXML) Then ReadXML()
    End Sub
#End Region
    Protected Overrides Sub Finalize()
        WriteXML()
        MyBase.Finalize()
    End Sub
End Class
